package ren.kane.phoenix.thread;

/**
 * @author renrk(1275) on 2019-08-15 3:28 PM
 **/
public class ProCusTest {
    public static void main(String[] args) {
        Depository depository = new Depository(100);
        Producer producer = new Producer(depository);
        Customer customer = new Customer(depository);
        producer.produce(60);
        producer.produce(120);
        customer.customer(90);
        customer.customer(150);
        producer.produce(110);
    }
}

class Depository {
    private int capacity;
    private int size;

    public Depository(int capacity) {
        this.capacity = capacity;
        this.size = 0;
    }

    public synchronized void produce(int val) {
        try {
            int left = val;
            while (left > 0) {
                while (size >= capacity) {
                    wait();
                }
                int inc = left + size > capacity ? (capacity - size) : left;
                size += inc;
                left -= inc;
                System.out.printf("%s produce(%3d) --> left=%3d, inc=%3d, size=%3d\n", Thread.currentThread().getName(), val, left, inc, size);
                notifyAll();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized void consume(int val) {
        try {
            int left = val;
            while (left > 0) {
                while (size <= 0) {
                    wait();
                }
                int dec = size < left ? size : left;
                size -= dec;
                left -= dec;
                System.out.printf("%s consume(%3d) <-- left=%3d, dec=%3d, size=%3d\n", Thread.currentThread().getName(), val, left, dec, size);
                notifyAll();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public String toString() {
        return "capacity:" + capacity + ", actual size:" + size;
    }
}

class Producer {
    private Depository depository;

    public Producer(Depository depository) {
        this.depository = depository;
    }

    public void produce(final int val) {
        new Thread(() -> depository.produce(val)).start();
    }
}

class Customer {
    private Depository depository;

    public Customer(Depository depository) {
        this.depository = depository;
    }

    public void customer(final int val) {
        new Thread(() -> depository.consume(val)).start();
    }
}